Fix bug: validate <field> before <operation> to prevent <error/crash>#402
Fix bug: validate <field> before <operation> to prevent <error/crash>#402everettbu wants to merge 1 commit into
Conversation
Refactor mutation diagnostics for better clarity and specificity. Introduce checks for prior hoisted accesses and provide more detailed error messages.
Greptile SummaryThis PR refactors mutation diagnostic error handling to provide more specific error messages when hoisted context declarations are accessed before they are declared. However, the PR contains a critical syntax error that prevents compilation. Critical Issue:
Intended Changes (obscured by syntax error):
Confidence Score: 0/5
Important Files Changed
|
| + if ( | ||
| + mutationKind === 'mutate-frozen' && | ||
| + context.hoistedContextDeclarations.has( | ||
| + effect.value.identifier.declarationId, | ||
| + ) | ||
| + ) { | ||
| + const variable = | ||
| + effect.value.identifier.name !== null && | ||
| + effect.value.identifier.name.kind === 'named' | ||
| + ? `\`${effect.value.identifier.name.value}\`` | ||
| + : null; | ||
| + const hoistedAccess = context.hoistedContextDeclarations.get( | ||
| + effect.value.identifier.declarationId, | ||
| + ); | ||
| + | ||
| + // Only produce the specialized "accessed before it is declared" diagnostic | ||
| + // when we actually observed a prior distinct hoisted access location. | ||
| + // If we don't have a recorded prior access location (hoistedAccess === null) | ||
| + // or the prior access location is the same as the declaration, fall back to | ||
| + // the generic "This value cannot be modified" diagnostic below. | ||
| + if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) { | ||
| + const diagnostic = CompilerDiagnostic.create({ | ||
| + category: ErrorCategory.Immutability, | ||
| + reason: 'Cannot access variable before it is declared', | ||
| + description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time`, | ||
| + }); | ||
| + diagnostic.withDetails({ | ||
| + kind: 'error', | ||
| + loc: hoistedAccess.loc, | ||
| + message: `${variable ?? 'variable'} accessed before it is declared`, | ||
| + }); | ||
| + diagnostic.withDetails({ | ||
| + kind: 'error', | ||
| + loc: effect.value.loc, | ||
| + message: `${variable ?? 'variable'} is declared here`, | ||
| + }); | ||
| + | ||
| + applyEffect( | ||
| + context, | ||
| + state, | ||
| + { | ||
| + kind: 'MutateFrozen', | ||
| + place: effect.value, | ||
| + error: diagnostic, | ||
| + }, | ||
| + initialized, | ||
| + effects, | ||
| + ); | ||
| + } else { | ||
| + // No prior distinct hoisted access recorded: fall back to the generic diagnostic | ||
| + // that explains why the value cannot be modified. | ||
| + const reason = getWriteErrorReason({ | ||
| + kind: value.kind, | ||
| + reason: value.reason, | ||
| + }); | ||
| + const variableName = | ||
| + effect.value.identifier.name !== null && | ||
| + effect.value.identifier.name.kind === 'named' | ||
| + ? `\`${effect.value.identifier.name.value}\`` | ||
| + : 'value'; | ||
| + const diagnostic = CompilerDiagnostic.create({ | ||
| + category: ErrorCategory.Immutability, | ||
| + reason: 'This value cannot be modified', | ||
| + description: reason, | ||
| + }).withDetails({ | ||
| + kind: 'error', | ||
| + loc: effect.value.loc, | ||
| + message: `${variableName} cannot be modified`, | ||
| + }); | ||
| + if ( | ||
| + effect.kind === 'Mutate' && | ||
| + effect.reason?.kind === 'AssignCurrentProperty' | ||
| + ) { | ||
| + diagnostic.withDetails({ | ||
| + kind: 'hint', | ||
| + message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`, | ||
| + }); | ||
| + } | ||
| + | ||
| + applyEffect( | ||
| + context, | ||
| + state, | ||
| + { | ||
| + kind: | ||
| + value.kind === ValueKind.Frozen ? 'MutateFrozen' : 'MutateGlobal', | ||
| + place: effect.value, | ||
| + error: diagnostic, | ||
| + }, | ||
| + initialized, | ||
| + effects, | ||
| + ); | ||
| + } | ||
| + } else { |
There was a problem hiding this comment.
syntax: Invalid syntax: literal + characters at the start of lines
This entire code block has diff markers (+) that were not removed during merge/patch application. These are literal characters in the source file, not just visual diff indicators. This will cause compilation to fail.
Remove the leading + characters from all lines in this range (92 lines total from line 1263-1355).
| + if ( | |
| + mutationKind === 'mutate-frozen' && | |
| + context.hoistedContextDeclarations.has( | |
| + effect.value.identifier.declarationId, | |
| + ) | |
| + ) { | |
| + const variable = | |
| + effect.value.identifier.name !== null && | |
| + effect.value.identifier.name.kind === 'named' | |
| + ? `\`${effect.value.identifier.name.value}\`` | |
| + : null; | |
| + const hoistedAccess = context.hoistedContextDeclarations.get( | |
| + effect.value.identifier.declarationId, | |
| + ); | |
| + | |
| + // Only produce the specialized "accessed before it is declared" diagnostic | |
| + // when we actually observed a prior distinct hoisted access location. | |
| + // If we don't have a recorded prior access location (hoistedAccess === null) | |
| + // or the prior access location is the same as the declaration, fall back to | |
| + // the generic "This value cannot be modified" diagnostic below. | |
| + if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) { | |
| + const diagnostic = CompilerDiagnostic.create({ | |
| + category: ErrorCategory.Immutability, | |
| + reason: 'Cannot access variable before it is declared', | |
| + description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time`, | |
| + }); | |
| + diagnostic.withDetails({ | |
| + kind: 'error', | |
| + loc: hoistedAccess.loc, | |
| + message: `${variable ?? 'variable'} accessed before it is declared`, | |
| + }); | |
| + diagnostic.withDetails({ | |
| + kind: 'error', | |
| + loc: effect.value.loc, | |
| + message: `${variable ?? 'variable'} is declared here`, | |
| + }); | |
| + | |
| + applyEffect( | |
| + context, | |
| + state, | |
| + { | |
| + kind: 'MutateFrozen', | |
| + place: effect.value, | |
| + error: diagnostic, | |
| + }, | |
| + initialized, | |
| + effects, | |
| + ); | |
| + } else { | |
| + // No prior distinct hoisted access recorded: fall back to the generic diagnostic | |
| + // that explains why the value cannot be modified. | |
| + const reason = getWriteErrorReason({ | |
| + kind: value.kind, | |
| + reason: value.reason, | |
| + }); | |
| + const variableName = | |
| + effect.value.identifier.name !== null && | |
| + effect.value.identifier.name.kind === 'named' | |
| + ? `\`${effect.value.identifier.name.value}\`` | |
| + : 'value'; | |
| + const diagnostic = CompilerDiagnostic.create({ | |
| + category: ErrorCategory.Immutability, | |
| + reason: 'This value cannot be modified', | |
| + description: reason, | |
| + }).withDetails({ | |
| + kind: 'error', | |
| + loc: effect.value.loc, | |
| + message: `${variableName} cannot be modified`, | |
| + }); | |
| + if ( | |
| + effect.kind === 'Mutate' && | |
| + effect.reason?.kind === 'AssignCurrentProperty' | |
| + ) { | |
| + diagnostic.withDetails({ | |
| + kind: 'hint', | |
| + message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`, | |
| + }); | |
| + } | |
| + | |
| + applyEffect( | |
| + context, | |
| + state, | |
| + { | |
| + kind: | |
| + value.kind === ValueKind.Frozen ? 'MutateFrozen' : 'MutateGlobal', | |
| + place: effect.value, | |
| + error: diagnostic, | |
| + }, | |
| + initialized, | |
| + effects, | |
| + ); | |
| + } | |
| + } else { | |
| if ( | |
| mutationKind === 'mutate-frozen' && | |
| context.hoistedContextDeclarations.has( | |
| effect.value.identifier.declarationId, | |
| ) | |
| ) { | |
| const variable = | |
| effect.value.identifier.name !== null && | |
| effect.value.identifier.name.kind === 'named' | |
| ? `\`${effect.value.identifier.name.value}\`` | |
| : null; | |
| const hoistedAccess = context.hoistedContextDeclarations.get( | |
| effect.value.identifier.declarationId, | |
| ); | |
| // Only produce the specialized "accessed before it is declared" diagnostic | |
| // when we actually observed a prior distinct hoisted access location. | |
| // If we don't have a recorded prior access location (hoistedAccess === null) | |
| // or the prior access location is the same as the declaration, fall back to | |
| // the generic "This value cannot be modified" diagnostic below. | |
| if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) { | |
| const diagnostic = CompilerDiagnostic.create({ | |
| category: ErrorCategory.Immutability, | |
| reason: 'Cannot access variable before it is declared', | |
| description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time`, | |
| }); | |
| diagnostic.withDetails({ | |
| kind: 'error', | |
| loc: hoistedAccess.loc, | |
| message: `${variable ?? 'variable'} accessed before it is declared`, | |
| }); | |
| diagnostic.withDetails({ | |
| kind: 'error', | |
| loc: effect.value.loc, | |
| message: `${variable ?? 'variable'} is declared here`, | |
| }); | |
| applyEffect( | |
| context, | |
| state, | |
| { | |
| kind: 'MutateFrozen', | |
| place: effect.value, | |
| error: diagnostic, | |
| }, | |
| initialized, | |
| effects, | |
| ); | |
| } else { | |
| // No prior distinct hoisted access recorded: fall back to the generic diagnostic | |
| // that explains why the value cannot be modified. | |
| const reason = getWriteErrorReason({ | |
| kind: value.kind, | |
| reason: value.reason, | |
| }); | |
| const variableName = | |
| effect.value.identifier.name !== null && | |
| effect.value.identifier.name.kind.kind === 'named' | |
| ? `\`${effect.value.identifier.name.value}\`` | |
| : 'value'; | |
| const diagnostic = CompilerDiagnostic.create({ | |
| category: ErrorCategory.Immutability, | |
| reason: 'This value cannot be modified', | |
| description: reason, | |
| }).withDetails({ | |
| kind: 'error', | |
| loc: effect.value.loc, | |
| message: `${variableName} cannot be modified`, | |
| }); | |
| if ( | |
| effect.kind === 'Mutate' && | |
| effect.reason?.kind === 'AssignCurrentProperty' | |
| ) { | |
| diagnostic.withDetails({ | |
| kind: 'hint', | |
| message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`, | |
| }); | |
| } | |
| applyEffect( | |
| context, | |
| state, | |
| { | |
| kind: | |
| value.kind === ValueKind.Frozen ? 'MutateFrozen' : 'MutateGlobal', | |
| place: effect.value, | |
| error: diagnostic, | |
| }, | |
| initialized, | |
| effects, | |
| ); | |
| } | |
| } else { |
Prompt To Fix With AI
This is a comment left during a code review.
Path: compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts
Line: 1263:1355
Comment:
**syntax:** Invalid syntax: literal `+` characters at the start of lines
This entire code block has diff markers (`+`) that were not removed during merge/patch application. These are literal characters in the source file, not just visual diff indicators. This will cause compilation to fail.
Remove the leading `+` characters from all lines in this range (92 lines total from line 1263-1355).
```suggestion
if (
mutationKind === 'mutate-frozen' &&
context.hoistedContextDeclarations.has(
effect.value.identifier.declarationId,
)
) {
const variable =
effect.value.identifier.name !== null &&
effect.value.identifier.name.kind === 'named'
? `\`${effect.value.identifier.name.value}\``
: null;
const hoistedAccess = context.hoistedContextDeclarations.get(
effect.value.identifier.declarationId,
);
// Only produce the specialized "accessed before it is declared" diagnostic
// when we actually observed a prior distinct hoisted access location.
// If we don't have a recorded prior access location (hoistedAccess === null)
// or the prior access location is the same as the declaration, fall back to
// the generic "This value cannot be modified" diagnostic below.
if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) {
const diagnostic = CompilerDiagnostic.create({
category: ErrorCategory.Immutability,
reason: 'Cannot access variable before it is declared',
description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time`,
});
diagnostic.withDetails({
kind: 'error',
loc: hoistedAccess.loc,
message: `${variable ?? 'variable'} accessed before it is declared`,
});
diagnostic.withDetails({
kind: 'error',
loc: effect.value.loc,
message: `${variable ?? 'variable'} is declared here`,
});
applyEffect(
context,
state,
{
kind: 'MutateFrozen',
place: effect.value,
error: diagnostic,
},
initialized,
effects,
);
} else {
// No prior distinct hoisted access recorded: fall back to the generic diagnostic
// that explains why the value cannot be modified.
const reason = getWriteErrorReason({
kind: value.kind,
reason: value.reason,
});
const variableName =
effect.value.identifier.name !== null &&
effect.value.identifier.name.kind.kind === 'named'
? `\`${effect.value.identifier.name.value}\``
: 'value';
const diagnostic = CompilerDiagnostic.create({
category: ErrorCategory.Immutability,
reason: 'This value cannot be modified',
description: reason,
}).withDetails({
kind: 'error',
loc: effect.value.loc,
message: `${variableName} cannot be modified`,
});
if (
effect.kind === 'Mutate' &&
effect.reason?.kind === 'AssignCurrentProperty'
) {
diagnostic.withDetails({
kind: 'hint',
message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`,
});
}
applyEffect(
context,
state,
{
kind:
value.kind === ValueKind.Frozen ? 'MutateFrozen' : 'MutateGlobal',
place: effect.value,
error: diagnostic,
},
initialized,
effects,
);
}
} else {
```
How can I resolve this? If you propose a fix, please make it concise.|
This pull request has been automatically marked as stale. If this pull request is still relevant, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated. |
|
Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you! |
Mirror of facebook/react#35597
Original author: harshilparekh874
Refactor mutation diagnostics for better clarity and specificity. Introduce checks for prior hoisted accesses and provide more detailed error messages.
Summary
How did you test this change?